#include "Music.h"
#include <unistd.h>
#include <dirent.h>

#define LYRIC_CACHE_LINES (LYRIC_SHOW_LINES + 4)

#define MUSIC_DIR "/overlay/musics/"
#define LYRIC_DIR "/overlay/musics/lyric/"

/**
  *@brief MainPage构造函数
  *@param exit_cb 退出进程回调函数
  */
Music::Music(function<void(void)> exitCb, mutex &UIMutex)
{
    threadExitFlag = false;
    ui_mutex = &UIMutex;

    //设置UI回调函数
    MusicUI::Operations uiOpts = {0};
    uiOpts.exitCb = exitCb;
    uiOpts.getStateCb = std::bind(&Music::getState, this);
    uiOpts.pauseCb = std::bind(&Music::pause, this);
    uiOpts.playCb = std::bind(&Music::play, this, std::placeholders::_1, std::placeholders::_2);    
    uiOpts.setCurCb = std::bind(&Music::setCur, this, std::placeholders::_1);
    uiOpts.setVolumeCb = snd_set_volume;
    uiOpts.getVolumeCb = snd_get_volume;
    uiOpts.getModeCb = std::bind(&Music::getMode, this);
    uiOpts.setModeCb = std::bind(&Music::setMode, this, std::placeholders::_1);

    MusicUI::create(uiOpts);

    pThread = new thread(&Music::threadFunction, this);           //创建执行线程
}

Music::~Music()
{
    threadExitFlag = true;
    pThread->join();
    delete pThread;

    MusicUI::release();
}

/**
  *@brief 搜索某个目录下的音频文件,支持MP3 WAV
  *@param path 目录路径
  *@return 搜索到的音乐个数
  */
int Music::searchMusic(string path)
{
    int cnt = 0;
    int i;
    bool legalMusic = false;
    std::string filePath;

    struct dirent *ent;
    DIR *dir = opendir(path.c_str());

    for (i = 0; ; i++)
    {
        ent = readdir(dir);
        if (ent == nullptr)
            break;

        if (ent->d_type == DT_REG)
        {
            const char *pfile = strrchr(ent->d_name, '.');
            if (pfile != nullptr)
            {
                filePath = path + std::string(ent->d_name);

                if (strcasecmp(pfile, ".wav") == 0)
                {
                    printf("wav file\n");
                    legalMusic = true;
                }
                else if (strcasecmp(pfile, ".mp3") == 0)
                {
                    printf("mp3 file\n");
                    legalMusic = true;
                }

            }
        }
        if (legalMusic == true)
        {
            legalMusic = false;
            ui_mutex->lock();
            MusicUI::addMusicList(ent->d_name);
            ui_mutex->unlock();
            
            cnt++;
        }

        usleep(50000);
    }

    closedir(dir);

    return cnt;
}

int Music::threadFunction()
{
    int tick = 0;
    usleep(50000);

    musicNum = searchMusic(MUSIC_DIR);

    while (!threadExitFlag)
    {
        ui_mutex->lock();

        if(musicObj != nullptr)
            MusicUI::setPlayProgress(musicObj->getCurTime(), musicObj->getTotalTime());
        if(musicLyric != nullptr)
        {
            int id = lyric_getid_by_time(musicLyric, musicObj->getCurTime() * 1000);

            MusicUI::setLyricId(id, true);
        }

        if(tick++ == 10)
        {
            tick = 0;
            if(musicObj != nullptr && musicObj->isOver() == true)
                changeMusic();           //根据当前模式切歌
        }
        ui_mutex->unlock();

        usleep(50000);
    }

    if(musicObj != nullptr)
        delete musicObj;

    return 0;
}

/**
  *@brief 切歌
  */
void Music::changeMusic(void)
{
    int max_index = musicNum - 1;

    switch(musicMode)
    {
        case MusicUI::PlayMode_ListLoop:
            musicIndex = musicIndex < max_index ? musicIndex + 1 : 0;           //顺序递增索引
        break;
        case MusicUI::PlayMode_SingleLoop:
            //musicIndex = musicIndex;                  //索引不变
        break;
        case MusicUI::PlayMode_Random:
        musicIndex = rand() % (max_index + 1);          //随机生成索引
        break;
    }
    const char *name = MusicUI::getMusicName(musicIndex);            //根据索引获取音乐文件名

    this->play(name, musicIndex);           //播放
}

/**
  *@brief 获取当前音乐的状态
  *@return 音乐状态 0 - 暂停状态       1 - 播放状态   -1 - 未播放(或播放结束)
  */
int Music::getState(void)
{
    if(musicObj != nullptr && musicObj->threadState != false)
        return (int)musicObj->getPlayState();
    else
        return -1;
}

/**
  *@brief 暂停音乐播放
  */
void Music::pause(void)
{
    if(musicObj != nullptr)
        musicObj->pause();
}

/***
  *@brief 播放音乐
  *@param name 切换的音乐文件名，若为nullptr则继续播放当前音乐
  *@param index 切换的音乐索引
  */
void Music::play(const char *name, int index)
{
    if(name == nullptr)                //不需要切歌
    {
        if(musicObj != nullptr)
            musicObj->play();
        return;
    }

    musicIndex =index;          //保存播放索引
    MusicUI::showMusicName(name);            //设置音乐名显示

    string filePath = MUSIC_DIR +  string(name);
    if(musicObj != nullptr)
        delete musicObj;            //删除先前的播放
    musicObj = nullptr;

    if(musicLyric != nullptr)  
        lyric_free(musicLyric);         //删除先前的歌词
    musicLyric = nullptr;

    musicObj = new MusicObj(filePath);
    musicObj->play();

    musicLyricSentences = 0;
    filePath = LYRIC_DIR + string(name);
    size_t pos = filePath.find('.');
    if(pos != string::npos)
    {
        filePath.erase(pos);
        filePath += ".lrc";
        musicLyric = lyric_load_from_file(filePath.c_str());
        if(musicLyric != nullptr)
        {
            musicLyricSentences = lyric_get_sentence_cnt(musicLyric);
            const char *lyric_n = lyric_get_all(musicLyric, '\n');
            MusicUI::loadLyric(lyric_n);            //装载歌词到UI
            if(lyric_n != nullptr)     // UI内部拷贝，此处可以释放
                free((void *)lyric_n);
        }
        else
            MusicUI::loadLyric(nullptr);            //指示找不到歌词
    }
    
}

/**
  *@brief 设置音乐播放时间点
  *@param cur_sec 设置的播放时间点，单位sec
  */
void Music::setCur(int cur_sec)
{
    if(musicObj != nullptr)
        musicObj->setCurTime(cur_sec);
}

/**
  *@brief 设置音乐播放模式
  *@param mode
  */
void Music::setMode(MusicUI::PlayMode mode)
{
    musicMode = mode;
}

/**
  *@brief 获取当前音乐播放模式
  *@param mode
  */
MusicUI::PlayMode Music::getMode(void)
{
    return musicMode;
}

